package ar.com.e2solver.solver.operator.localsearch.mt;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import ar.com.e2solver.exception.BusinessException;
import ar.com.e2solver.solver.Individual;
import ar.com.e2solver.solver.operator.localsearch.HillClimbing;

public abstract class MultiThreadHillClimbing implements HillClimbing {
	
	private static final int N_THREADS = 2;
	
	public List<Individual> climb(Collection<Individual> selectedIndividuals) throws BusinessException {
		List<Individual> result = Collections.synchronizedList(new ArrayList<Individual>());
		
		ExecutorService executor = Executors.newFixedThreadPool(this.getThreadsNumber());
		int i = 0;
		
		Individual individual;
		for (Iterator<Individual> iterator = selectedIndividuals.iterator(); iterator.hasNext();) {
			individual = iterator.next();
			Runnable worker = this.getClimbWorker(individual, result, i);
			executor.execute(worker);
			i++;
		}
		
		executor.shutdown();
		
		// Espera a que todos los threads hayan terminado
		while (!executor.isTerminated()) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				throw new BusinessException("Error esperando threads", e);
			}
		}
		
		return result;
	}
	
	protected int getThreadsNumber(){
		return N_THREADS;
	}
	
	protected abstract ClimbWorker getClimbWorker(Individual individual, List<Individual> result, int identifier);
		
}
